package com.litengsoft.lianmeng.common;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * @author zhangfatao
 * @date 2019-05-27 17:33
 * @desc apache http client工具类
 **/
public final class HttpUtils {

    private static final RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(1000)
            .setConnectTimeout(1000)
            .setConnectionRequestTimeout(1000)
            .build();

    private HttpUtils() {
    }

    /**
     * 发送get请求
     *
     * @param url 请求url
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(String url) throws IOException, URISyntaxException {
        return sendHttpGet(URI.create(url));
    }

    /**
     * 发送get请求
     *
     * @param url 请求url
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(URL url) throws IOException, URISyntaxException {
        return sendHttpGet(url.toURI());
    }

    private static String sendHttpGet(URI uri) throws IOException, URISyntaxException {
        return sendHttpGet(uri, null, null);
    }

    /**
     * 发送get请求
     *
     * @param url    请求url
     * @param params 请求参数
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(String url, Map<String, String> params) throws IOException, URISyntaxException {
        return sendHttpGet(URI.create(url), params);
    }

    /**
     * 发送get请求
     *
     * @param url    请求url
     * @param params 请求参数
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(URL url, Map<String, String> params) throws IOException, URISyntaxException {
        return sendHttpGet(url.toURI(), params);
    }

    private static String sendHttpGet(URI uri, Map<String, String> params) throws IOException, URISyntaxException {
        return sendHttpGet(uri, params, null);
    }

    /**
     * 发送get请求
     *
     * @param url     请求url
     * @param params  请求参数
     * @param headers 请求头参数
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(String url, Map<String, String> params, Map<String, String> headers)
            throws IOException, URISyntaxException {
        return sendHttpGet(URI.create(url), params, headers);
    }

    /**
     * 发送get请求
     *
     * @param url     请求url
     * @param params  请求参数
     * @param headers 请求头参数
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpGet(URL url, Map<String, String> params, Map<String, String> headers)
            throws IOException, URISyntaxException {
        return sendHttpGet(url.toURI(), params, headers);
    }

    public static String sendHttpGet(URI uri, Map<String, String> params, Map<String, String> headers)
            throws IOException, URISyntaxException {
        String responseBody = null;

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            URIBuilder builder = new URIBuilder(uri);
            if (params != null) {
                params.forEach(builder::addParameter);
            }

            HttpGet httpGet = new HttpGet(builder.build());
            httpGet.setConfig(requestConfig);
            if (headers != null) {
                headers.forEach(httpGet::addHeader);
            }

            HttpEntity entity = httpClient.execute(httpGet).getEntity();
            if (entity != null && StringUtils.isNotBlank(entity.getContentType().getValue())
                    && entity.getContentType().getValue().toLowerCase().contains("image")) {
                InputStream inputStream = entity.getContent();
                byte[] data = null;
                ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
                byte[] buff = new byte[100];
                int rc = 0;
                try {
                    while ((rc = inputStream.read(buff, 0, 100)) > 0) {
                        swapStream.write(buff, 0, rc);
                    }
                    data = swapStream.toByteArray();
                    responseBody = "data:" + entity.getContentType().getValue() + ";base64,"
                            + new String(Base64.getEncoder().encode(data));
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    swapStream.close();
                }
            } else {
                responseBody = httpClient.execute(httpGet, response -> EntityUtils.toString(response.getEntity(), "UTF-8"));
            }
        }

        return responseBody;
    }

    /**
     * 请求链接获取cookie
     *
     * @param url
     * @param params
     * @param headers
     * @return
     * @throws IOException
     * @throws URISyntaxException
     */
    public static List<Cookie> sendHttpGetAndGetCookie(String url, Map<String, String> params, Map<String, String> headers)
            throws IOException, URISyntaxException {
        String responseBody = null;
        CookieStore cookieStore = new BasicCookieStore();

        try (CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build()) {
            URI uri = URI.create(url);
            URIBuilder builder = new URIBuilder(uri);
            if (params != null) {
                params.forEach(builder::addParameter);
            }
            HttpGet httpGet = new HttpGet(builder.build());
            httpGet.setConfig(requestConfig);
            if (headers != null) {
                headers.forEach(httpGet::addHeader);
            }

            HttpEntity entity = httpClient.execute(httpGet).getEntity();
            return cookieStore.getCookies();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送post请求
     *
     * @param url 请求url
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpPost(String url) throws IOException, URISyntaxException {
        return sendHttpPost(URI.create(url));
    }

    /**
     * 发送post请求
     *
     * @param url 请求url
     * @return 请求结果
     * @throws IOException
     * @throws URISyntaxException
     */
    public static String sendHttpPost(URL url) throws URISyntaxException, IOException {
        return sendHttpPost(url.toURI());
    }

    private static String sendHttpPost(URI uri) throws URISyntaxException, IOException {
        HttpPost httpPost = new HttpPost(uri);
        return sendHttpPost(httpPost);
    }

    /**
     * 发送post请求
     *
     * @param url    请求url
     * @param params post参数
     * @return 请求结果
     * @throws IOException
     */
    public static String sendHttpPost(String url, String params) throws IOException, URISyntaxException {
        return sendHttpPost(URI.create(url), params);
    }

    /**
     * 发送post请求
     *
     * @param url    请求url
     * @param params post参数
     * @return 请求结果
     * @throws IOException
     */
    public static String sendHttpPost(URL url, String params) throws IOException, URISyntaxException {
        return sendHttpPost(url.toURI(), params);
    }

    private static String sendHttpPost(URI uri, String params) throws IOException, URISyntaxException {
        HttpPost httpPost = new HttpPost(uri);
        StringEntity stringEntity = new StringEntity(params, "UTF-8");
        stringEntity.setContentType("application/x-www-form-urlencoded");
        httpPost.setEntity(stringEntity);

        return sendHttpPost(httpPost);
    }

    /**
     * 发送post请求
     *
     * @param url   请求url
     * @param pairs post参数
     * @return 结果future
     * @throws IOException
     */
    public static String sendHttpPost(String url, Map<String, String> pairs) throws IOException, URISyntaxException {
        return sendHttpPost(URI.create(url));
    }

    /**
     * 发送post请求
     *
     * @param url   请求url
     * @param pairs post参数
     * @return 结果future
     * @throws IOException
     */
    public static String sendHttpPost(URL url, Map<String, String> pairs) throws IOException, URISyntaxException {
        return sendHttpPost(url.toURI(), pairs);
    }

    private static String sendHttpPost(URI uri, Map<String, String> pairs) throws IOException {
        HttpPost httpPost = new HttpPost(uri);

        if (pairs != null) {
            List<NameValuePair> nameValuePairs = new ArrayList<>();
            pairs.forEach((key, value) -> nameValuePairs.add(new BasicNameValuePair(key, value)));
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
        }

        return sendHttpPost(httpPost);
    }

    /**
     * 发送带文件形式post请求
     *
     * @param url       请求url
     * @param pairs     请求参数
     * @param fileLists 文件参数
     * @return 结果future
     * @throws IOException
     */
    public static String sendHttpPost(String url, Map<String, String> pairs, List<File> fileLists) throws IOException {
        return sendHttpPost(URI.create(url), pairs, fileLists);
    }

    /**
     * 发送带文件形式post请求
     *
     * @param url       请求url
     * @param pairs     请求参数
     * @param fileLists 文件参数
     * @return 结果future
     * @throws IOException
     */
    public static String sendHttpPost(URL url, Map<String, String> pairs, List<File> fileLists)
            throws IOException, URISyntaxException {
        return sendHttpPost(url.toURI(), pairs, fileLists);
    }

    /**
     * 发送带文件形式post请求
     *
     * @param uri       请求uri
     * @param pairs     请求参数
     * @param fileLists 文件参数
     * @return 结果future
     * @throws IOException
     */
    public static String sendHttpPost(URI uri, Map<String, String> pairs, List<File> fileLists) throws IOException {
        return sendHttpPost(buildHttpPost(uri, pairs, fileLists));
    }

    private static String sendHttpPost(HttpPost httpPost) throws IOException {
        String responseBody;

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            httpPost.setConfig(requestConfig);
            responseBody = httpClient.execute(httpPost, response -> EntityUtils.toString(response.getEntity(), "UTF-8"));
        }

        return responseBody;
    }

    private static HttpPost buildHttpPost(URI uri, Map<String, String> pairs, List<File> fileLists) {
        HttpPost httpPost = new HttpPost(uri);

        if (pairs != null || fileLists != null) {
            MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create();

            if (pairs != null) {
                pairs.forEach((key, value) -> meBuilder.addPart(key, new StringBody(value, ContentType.TEXT_PLAIN)));
            }

            if (fileLists != null) {
                fileLists.forEach(file -> meBuilder.addPart("file", new FileBody(file)));
            }

            HttpEntity reqEntity = meBuilder.build();
            httpPost.setEntity(reqEntity);
        }

        return httpPost;
    }

    /**
     * 获取用户真实ip
     *
     * @param request
     * @return
     */
    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotBlank(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个ip值，第一个ip才是真实ip
            int index = ip.indexOf(",");
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        ip = request.getHeader("X-Real-IP");
        if (!StringUtils.isBlank(ip) && !"unKnown".equalsIgnoreCase(ip)) {
            return ip;
        }
        return request.getRemoteAddr();
    }

}
